package com.example.apptest.utils;


import android.annotation.SuppressLint;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothManager;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.le.BluetoothLeScanner;
import android.bluetooth.le.ScanCallback;
import android.bluetooth.le.ScanFilter;
import android.bluetooth.le.ScanResult;
import android.bluetooth.le.ScanSettings;
import android.content.Context;
import android.util.Log;

import com.example.apptest.App;
import com.example.apptest.events.EventLEDStatus;
import com.example.apptest.events.EventNotifyChange;
import com.example.apptest.events.EventScanResult;
import com.example.apptest.events.EventSpinMove;

import org.greenrobot.eventbus.EventBus;

import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

import androidx.annotation.NonNull;

public class BLEHelper {

    private BluetoothAdapter mBLEAdapter;
    private BluetoothLeScanner mScanner;
    private boolean isScanning = false;
    private boolean isNotify = false;
    private BluetoothGatt mGatt;
    private final String CharConfigUUID = "00002902-0000-1000-8000-00805f9b34fb";
    private BluetoothGattCharacteristic LEDCharacter;
    private BluetoothGattCharacteristic controlCharacter;

    private BLEHelper() {
        BluetoothManager manager = (BluetoothManager)App.AppContext
                .getSystemService(Context.BLUETOOTH_SERVICE);
        mBLEAdapter = manager.getAdapter();
    }
    private static BLEHelper instance;
    public static BLEHelper getInstance() {
        if(instance == null) instance = new BLEHelper();
        return instance;
    }
    private void setNotify(BluetoothGatt gatt, BluetoothGattCharacteristic character, boolean what) {
        if(isNotify == what)
            return;

        boolean result = gatt.setCharacteristicNotification(character, what);
        if(result) {
            BluetoothGattDescriptor descriptor = character.getDescriptor(UUID.fromString(CharConfigUUID));
            if(descriptor != null) {
                descriptor.setValue(what ? BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE : BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE);
                gatt.writeDescriptor(descriptor);
            }
        }
    }
    private final BluetoothGattCallback gattCallback = new BluetoothGattCallback() {

        @Override
        public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
            if(descriptor.getUuid().equals(UUID.fromString(CharConfigUUID))) {
                isNotify = descriptor.getValue().equals(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
                EventBus.getDefault().post(new EventNotifyChange(isNotify));
            }
        }

        @Override
        public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
            if (newState == BluetoothProfile.STATE_CONNECTED) {
                gatt.discoverServices();
            } else if(newState == BluetoothProfile.STATE_DISCONNECTED) {
                gatt.close();
            }
        }

        private final String ServiceUUID = "0000fff0-0000-1000-8000-00805f9b34fb";
        //        private final String CharUUID_W = "0000fff2-0000-1000-8000-00805f9b34fb";
        private final String LEDCharUUID = "0000fff1-0000-1000-8000-00805f9b34fb";
        private final String ctrlCharUUID = "0000fff6-0000-1000-8000-00805f9b34fb";

        @SuppressLint("MissingPermission")
        @Override
        public void onServicesDiscovered(BluetoothGatt gatt, int status) {
            if (status == BluetoothGatt.GATT_SUCCESS) {
                List<BluetoothGattService> serviceList = gatt.getServices();
                for (BluetoothGattService service : serviceList) {
                    if (service.getUuid().toString().equals(ServiceUUID)) {
//                        receiveCharacter = service.getCharacteristic(UUID.fromString(CharUUID_N));
//                        sendCharacter = service.getCharacteristic(UUID.fromString(CharUUID_W));
                        LEDCharacter = service.getCharacteristic(UUID.fromString(LEDCharUUID));
                        controlCharacter = service.getCharacteristic(UUID.fromString(ctrlCharUUID));
                        //setNotify(gatt, receiveCharacter, true);
                    }
                }
            }
        }

        @Override
        public void onCharacteristicChanged(@NonNull BluetoothGatt gatt, @NonNull BluetoothGattCharacteristic characteristic, @NonNull byte[] value) {
            //TODO 发送 EventBus 事件 携带数据
            Log.d("onCharacteristicChanged", value[0] + ":" +value[1]);
            EventBus.getDefault().post(new EventSpinMove(value));
        }

        @Override
        public void onCharacteristicRead(@NonNull BluetoothGatt gatt, @NonNull BluetoothGattCharacteristic characteristic, @NonNull byte[] value, int status) {
            if(characteristic.getUuid().equals(UUID.fromString(LEDCharUUID))) {
                EventBus.getDefault().post(new EventLEDStatus(value[0]));
            }
        }
    };

    private ScanCallback mScanCallback = new ScanCallback() {

        @SuppressLint("MissingPermission")
        @Override
        public void onScanResult(int callbackType, ScanResult result) {
            BluetoothDevice dev = result.getDevice();
            int rssi = result.getRssi();
            EventBus.getDefault().post(new EventScanResult(dev, rssi));
        }
    };



    public boolean ScanDevices() {
        if (isScanning)
            return true;
        if (mBLEAdapter != null) {
            if (mBLEAdapter.isEnabled()) {
                mScanner = mBLEAdapter.getBluetoothLeScanner();
                List<ScanFilter> filterList = new ArrayList<>();
                filterList.add(new ScanFilter.Builder()
                        //.setDeviceName("ABC")
                        .build());
                mScanner.startScan(filterList, new ScanSettings.Builder().build(), mScanCallback);
                isScanning = true;
                return true;
            }
        }
        return false;
    }

    @SuppressLint("MissingPermission")
    public void StopScan() {
        if (mScanner != null) {
            mScanner.stopScan(mScanCallback);
        }
        isScanning = false;
    }

    public void connectToDevice(BluetoothDevice dev) {
        if(mGatt != null) {
            mGatt.close();
            mGatt = null;
        }
        if (isScanning) {
            StopScan();
        }
        mGatt = dev.connectGatt(App.AppContext, false, gattCallback);
    }

    public void sendData(byte[] data) {
//        if(sendCharacter != null && mGatt != null) {
//            sendCharacter.setValue(data);
//            mGatt.writeCharacteristic(sendCharacter);
//        }
    }

    public void notifyToggle() {
        if(controlCharacter != null && mGatt != null) {
            setNotify(mGatt, controlCharacter, !isNotify);
        }
    }

    public void readLEDCharacter() {
        if(LEDCharacter != null && mGatt != null) {
            mGatt.readCharacteristic(LEDCharacter);
        }
    }

    @SuppressLint("MissingPermission")
    public void writeLEDCharacter(int val) {
        if(LEDCharacter != null && mGatt != null) {
            LEDCharacter.setValue(new byte[] {(byte)val});
            mGatt.writeCharacteristic(LEDCharacter);
        }
    }
}
